package com.zhdl.network.modbustcp;

import com.project.common.util.ByteHelper;
import com.zhdl.network.modbus.request.WriteSingleKeepRegisterReq;
import lombok.Data;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * 组装modbus-tcp响应数据包
 */
@Data
public class ModbusTcpRespPkg {
    /**
     * 根据数据单元组装完整响应数据包
     *
     * @param unitBuff
     * @return
     * @throws IOException
     */
    private static byte[] PkgFullFrame(byte[] unitBuff) throws IOException {
        ByteArrayOutputStream bw = new ByteArrayOutputStream();
        // 传输标识符 2HEX
        bw.write((byte) 0x00);
        bw.write((byte) 0x00);
        // 协议标识符 2HEX
        bw.write((byte) 0x00);
        bw.write((byte) 0x00);
        // 长度 2HEX 高字节在前
        short length = (short) (unitBuff.length + 1);
        bw.write((byte) ((length & 0xFF00)) >> 8); // DataNum(H)
        bw.write((byte) (length & 0x00FF)); // DataNum(L)
        // 站标识 目前固定为 0x01
        bw.write((byte) 0x01);
        // 具体指令的数据单元部分
        bw.write(unitBuff);

        return bw.toByteArray();
    }

    private static byte[] PkgFullFrameHaveID(byte[] unitBuff, int id) throws IOException {
        ByteArrayOutputStream bw = new ByteArrayOutputStream();
        // 传输标识符 2HEX
        bw.write((byte) 0x00);
        bw.write((byte) 0x00);
        // 协议标识符 2HEX
        bw.write((byte) 0x00);
        bw.write((byte) 0x00);
        // 长度 2HEX 高字节在前
        short length = (short) (unitBuff.length + 1);
        bw.write((byte) ((length & 0xFF00)) >> 8); // DataNum(H)
        bw.write((byte) (length & 0x00FF)); // DataNum(L)
        // 站标识 目前固定为 0x01
        bw.write((byte) id);
        // 具体指令的数据单元部分
        bw.write(unitBuff);

        return bw.toByteArray();
    }


//    /**
//     * 0x01 读线圈
//     *
//     * @param req
//     */
//    public static byte[] Read01(WriteSingleKeepRegisterReq req) throws IOException {
//        ByteArrayOutputStream bw = new ByteArrayOutputStream();
//        byte[] bsTemp;
//
//        // 功能码 1HEX
//        bw.write(ByteHelper.stringToBytes(req.id));
//
//        // 寄存器值 N*2HEX
//        bsTemp = (ByteHelper.stringToBytes(req.startAddr));
//        bw.write(bsTemp);
//
//        bw.write(ByteHelper.stringToBytes(req.writeValue));
//
//        return PkgFullFrame(bw.toByteArray());
//    }

    /**
     * 0x01 读线圈
     *
     * @param req
     */
    public static byte[] read01(WriteSingleKeepRegisterReq req) throws IOException {
        ByteArrayOutputStream bw = new ByteArrayOutputStream();
        byte[] bsTemp;

        // 功能码 1HEX
        bw.write(0x01);

        // 寄存器值 N*2HEX
        bsTemp = (ByteHelper.stringToBytes(req.startAddr));
        bw.write(bsTemp);

        bw.write(ByteHelper.stringToBytes(req.writeValue));

        int i = Integer.parseInt(req.id);
        return PkgFullFrameHaveID(bw.toByteArray(), i);
    }

    /**
     * 0x02 读离散量
     */
    public static byte[] read02(WriteSingleKeepRegisterReq req) throws IOException {
        ByteArrayOutputStream bw = new ByteArrayOutputStream();
        byte[] bsTemp;
        // 功能码 1HEX
        bw.write(0x02);

        // 寄存器值 N*2HEX
        bsTemp = (ByteHelper.stringToBytes(req.startAddr));
        bw.write(bsTemp);

        bw.write(ByteHelper.stringToBytes(req.writeValue));

        int i = Integer.parseInt(req.id);
        return PkgFullFrameHaveID(bw.toByteArray(), i);
    }

    /**
     * 0x05 写线圈
     *
     * @param req
     */
    public static byte[] write05(WriteSingleKeepRegisterReq req) throws IOException {
        ByteArrayOutputStream bw = new ByteArrayOutputStream();
        byte[] bsTemp;
        // 功能码 1HEX
        bw.write((byte) 0x05);

        // 寄存器值 N*2HEX
        bsTemp = (ByteHelper.stringToBytes(req.startAddr));
        bw.write(bsTemp);
        bsTemp = (ByteHelper.stringToBytes(req.writeValue));
        bw.write(bsTemp);
        int i = Integer.parseInt(req.id);
        return PkgFullFrameHaveID(bw.toByteArray(), i);
    }

    /**
     * 0x03 读保持寄存器
     *
     * @param req
     */
    public static byte[] ReadKeepRegister(WriteSingleKeepRegisterReq req) throws IOException {
        ByteArrayOutputStream bw = new ByteArrayOutputStream();
        byte[] bsTemp;

        // 功能码 1HEX
        bw.write((byte) 0x03);

        // 寄存器值 N*2HEX
        bsTemp = (ByteHelper.stringToBytes(req.startAddr));
        bw.write(bsTemp);

        bsTemp = (ByteHelper.stringToBytes(req.writeValue));
        bw.write(bsTemp);


        return PkgFullFrame(bw.toByteArray());
    }

    /**
     * 0x04 读输入寄存器
     *
     * @param req
     */
    public static byte[] ReadInputRegister(WriteSingleKeepRegisterReq req) throws IOException {
        ByteArrayOutputStream bw = new ByteArrayOutputStream();
        // 功能码 1HEX
        bw.write((byte) 0x04);
        // 寄存器值 N*2HEX
        byte[] bsTemp = bsTemp = (ByteHelper.stringToBytes(req.startAddr));
        bw.write(bsTemp);


        return PkgFullFrame(bw.toByteArray());
    }

    /**
     * 0x06 写单个保持寄存器
     *
     * @param req
     */
    public static byte[] WriteSingleKeepRegister(WriteSingleKeepRegisterReq req) throws IOException {
        ByteArrayOutputStream bw = new ByteArrayOutputStream();
        byte[] bsTemp;

        // 功能码 1HEX
        bw.write((byte) 0x06);
        // 寄存器值 N*2HEX
        bsTemp = (ByteHelper.stringToBytes(req.startAddr));
        bw.write(bsTemp);
        bsTemp = (ByteHelper.stringToBytes(req.getWriteValue()));
        bw.write(bsTemp);
        return PkgFullFrame(bw.toByteArray());
    }

    /**
     * 0x10 写多个连续保持寄存器
     *
     * @param req
     */
    public static byte[] WriteManyKeepRegister(WriteSingleKeepRegisterReq req) throws IOException {
        ByteArrayOutputStream bw = new ByteArrayOutputStream();
        byte[] bsTemp;

        // 功能码 1HEX
        bw.write((byte) 0x10);
        // 起始地址 2HEX 0x0000 至 0xFFFF
        bsTemp = (ByteHelper.stringToBytes(req.startAddr));
        bw.write(bsTemp);
        // 寄存器数量 2HEX 1~123(0x7B)
        bsTemp = ByteHelper.shortToByteArrayByHigh((short) (req.getWriteValue().length() / 4));
        bw.write(bsTemp);
        bw.write((byte) req.getWriteValue().length() / 2);
        bsTemp = (ByteHelper.stringToBytes(req.getWriteValue()));
        bw.write(bsTemp);
        return PkgFullFrame(bw.toByteArray());
    }

    /**
     * 0x0F 写多个线圈
     * 双线圈写入值 01 开 02 关
     *
     * @param req
     */
    public static byte[] WriteDoubleCoil(WriteSingleKeepRegisterReq req) throws IOException {
        ByteArrayOutputStream bw = new ByteArrayOutputStream();
        byte[] bsTemp;

        // 功能码 1HEX
        bw.write((byte) 0x0F);
        // 起始地址 2HEX 0x0000 至 0xFFFF
        bsTemp = (ByteHelper.stringToBytes(req.startAddr));
        bw.write(bsTemp);
        // 线圈写入数量 2HEX 1~123(0x7B)
        bw.write((byte) 0x00);
        bw.write((byte) 0x02);
        // 线圈字节数量
        bw.write((byte) 0x01);
        //写入值
        bsTemp = (ByteHelper.stringToBytes(req.getWriteValue()));
        bw.write(bsTemp);
        int i = Integer.parseInt(req.id);
        return PkgFullFrameHaveID(bw.toByteArray(), i);
//        return PkgFullFrame(bw.toByteArray());
    }


}
